package com.moqbus.service.schedule;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.apache.log4j.Logger;

import com.moqbus.service.application.Global;

import com.moqbus.service.common.constant.JbusConst;
import com.moqbus.service.common.helper.HexHelper;
import com.moqbus.service.db.mysql.bean.CmdEncodeEntity;
import com.moqbus.service.db.mysql.dao.CmdEncodeDao;
import com.moqbus.service.proxy.MqttProxy;


/* 
 *  批量/简短 指令的转发
 *  参考: cloud.jbus.logic.realtime.SendCmdLogic
 * 
 */
public class BatchCmdService {

	static Logger log = Logger.getLogger(BatchCmdService.class);
	
	// 22.5.8 命令缓存  "deviceId-sno:cmdNo" : cmdHex
	public static Map<String, String> CMD_CACHE_MAP = new HashMap<String, String>();
	/*
	 * cmd:
	 * 1) 单条，明码：11 22 33 44
	 * 2）单条，引用： 3:2 （sensorNo:cmdNo）
	 * 3）多条，明码：30;00 11,11 22,33 44  （ms;cmdstr1,cmdstr2,...)
	 * 4) 多条，引用：30;3:2,4:1 (ms;sensorNo1:cmdNo1, sensorNo2:cmdNo2)
	 */
	
	public static void receiveBatchCmd(String deviceSn, String batchCmd) {
		
		// remove cache: "remove_cache#{key}"
		if (batchCmd.startsWith("remove_cache")) {
			String key = batchCmd.split("#")[1];
			String removedVal = CMD_CACHE_MAP.remove(key);
			if (removedVal != null) {
				log.info(String.format("删除缓存：CMD_CACHE_MAP.%s: %s", key, removedVal));
			} else {
				log.info("尚未缓存：CMD_CACHE_MAP." + key);
			}
			
			return;
		}
		
		execute(deviceSn, batchCmd);
		
		
		
	}
	
	
	protected static boolean execute(String deviceSn, String cmd) {
		Date startTime = new Date();
		log.info("发送指令：开始");
		
		cmd = cmd.replaceAll(" ", "").replaceAll("	", ""); // 消除空白和tab

		log.info(String.format("    参数：deviceSn=%s, cmd=%s", deviceSn, cmd));
		
//		Integer deviceId = CommonLogic.getDeviceIdBySn(deviceSn);
		Integer deviceId = Global.cacheDevice.map.get(deviceSn).getId();
		
		if (cmd.indexOf(";")>0) { 
			// 多条指令: "30;00 11,11 22,33 44"
			String[] c = cmd.split(";");
			String[] cmds = c[1].split(",");
			log.info(String.format("    多条指令：%d 条", cmds.length));
			sendMutiCmd(deviceSn, deviceId, Integer.valueOf(c[0]) ,cmds);
			log.info(String.format("    多条响应：%d ms", (new Date().getTime()-startTime.getTime())));
			
		} else {

			// 单条指令
			log.info(String.format("    单条指令：%s", cmd));
			cmd = getDirectiveCmd(deviceId, cmd); // 引用转换
			log.info(String.format("    单条指令（转换后）：%s", cmd));
			
			String topic = JbusConst.TOPIC_PREFIX_CMD;
			if(cmd.startsWith("FW-")) {
				// 22.7.7 转发给plugin，为了对命令进行再加工，如设置消息序号。
				int firstBlank = cmd.indexOf(" ");
				topic = JbusConst.TOPIC_PREFIX_FWCMD + cmd.substring(3, firstBlank) + "-";
				cmd = cmd.substring(firstBlank+1);
			}

			byte[] data = HexHelper.hexStringToBytes(cmd);
			String topicDeviceSn = topic + deviceSn;
			
			// 22.8.19 未知原因，单条执行时，mqttclient 崩溃。 改成线程执行试试。
			new Thread(){

				@Override
				public void run() {
					MqttProxy.publish(topicDeviceSn, data);
					log.info(String.format("    单条响应：%d ms", (new Date().getTime()-startTime.getTime())));
				}
			}.start();
			
		}
		
		return true;
	}
	

	private static void sendMutiCmd(String deviceSn, Integer deviceId, Integer interval, String[] cmds) {
		
		
		new Thread(){

			@Override
			public void run() {

				Date startTime = new Date();
				log.info(String.format("多条Run：开始发送：%s, %d ms, %d 条", deviceSn, interval, cmds.length));
				int i = 0;
				for(String cmd: cmds) {
					
					try {

						Date startTimeOne = new Date();
						log.info(String.format("          单条Run %d：%s ", i, cmd));
						cmd = getDirectiveCmd(deviceId, cmd); // 引用转换
						log.info(String.format("          单条Run %d：%s ", i, cmd));
						String topic = JbusConst.TOPIC_PREFIX_CMD;
						if(cmd.startsWith("FW-")) {
							int firstBlank = cmd.indexOf(" ");
							topic = JbusConst.TOPIC_PREFIX_FWCMD + cmd.substring(3, firstBlank) + "-";
							cmd = cmd.substring(firstBlank+1);
						}
						
						byte[] data = HexHelper.hexStringToBytes(cmd);
						MqttProxy.publish(topic + deviceSn, data);
						log.info(String.format("          单条Run %d: 耗时 %d ms", i, new Date().getTime()-startTimeOne.getTime()));
						i++;
					} catch (Exception e) {
						log.error(e);  // 一条指令错误，不影响其它指令的执行。
					}
					
					try {
						Thread.sleep(interval);
					} catch (InterruptedException e) {
						log.error(e);
					}
				}

				log.info(String.format("多条Run：累计耗时：%d ms", new Date().getTime()-startTime.getTime()));
			}

			
		}.start();
	}
	

	private static String getDirectiveCmd(Integer deviceId, String cmd) {

		if(cmd.contains(":")) {
			// 22.5.8 缓存
			log.info(String.format("    CMD_CACHE_MAP: %d 条", CMD_CACHE_MAP.size()));
			String key = String.format("%d-%s", deviceId, cmd);
			if (CMD_CACHE_MAP.containsKey(key)) {
				cmd = CMD_CACHE_MAP.get(key);
				log.info(String.format("    CMD_CACHE_MAP 命中 %s , %s", key, cmd));
			} else {
				// 引用
				String[] cmds = cmd.split(":");
				Integer sensorNo = Integer.valueOf(cmds[0]);
				Integer cmdNo = Integer.valueOf(cmds[1]);
//				Integer sensorId = getSensorIdByNo(deviceId, sensorNo);
				cmd = getCmdBySnoCmdNo(deviceId, sensorNo, cmdNo);
				CMD_CACHE_MAP.put(key, cmd);
				log.info(String.format("    CMD_CACHE_MAP 加入 %s , %s", key, cmd));
			}

			log.info(String.format("    CMD_CACHE_MAP: %d 条", CMD_CACHE_MAP.size()));
		} else {

			// 明码
			// 不转换
		}
		
		return cmd;
	}
	
	
	private static String getCmdBySnoCmdNo(Integer deviceId, Integer sensorNo, Integer cmdNo) {

		CmdEncodeEntity cmdEntity = CmdEncodeDao.findBySnoCmdNo(deviceId, sensorNo, cmdNo);
		String script;
		if (cmdEntity != null) {
			script = cmdEntity.getScriptText();

			if(script.contains("function")) {
				script = script.split("'")[1];
			}
		} else {
			script = "EE EE EE 02"; //  设置错误
			log.error(String.format("script 不存在：sn=%d, sno=%d, cmdNo=%d", deviceId, sensorNo, cmdNo));
		}
			
		return script;

	}
	
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}

}
